package gdma.hqdes.webapp.controller;

import common.annotation.Traced;
import common.exception.NotFoundException;
import gdma.hqdes.bean.Unit;
import gdma.hqdes.bean.UnitMember;
import gdma.hqdes.service.UnitService;
import gdma.hqdes.webapp.util.PinyinUtils;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import org.apache.shiro.authz.AuthorizationException;
import org.apache.shiro.authz.annotation.Logical;
import org.apache.shiro.authz.annotation.RequiresPermissions;
import org.apache.shiro.authz.annotation.RequiresRoles;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.dao.DuplicateKeyException;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.*;
import sindconsole.auth.bean.Account;
import sindconsole.auth.bean.Role;
import sindconsole.auth.service.AuthService;
import springfox.documentation.annotations.ApiIgnore;

import java.util.*;
import java.util.stream.Collectors;

import static gdma.hqdes.Constants.*;

/**
 * @Author wangyue
 * @Version 3.0
 * @Date 2024-07-14
 */

@RestController
@RequestMapping("/api/admin/units")
public class UnitAdminController {

    public static final String DEFAULT_PASSWORD = "Passw0rd";

    @Autowired
    UnitService unitService;

    @Autowired
    AuthService authService;

    @ApiOperation("单位列表")
    @GetMapping("")
    @RequiresPermissions("units:global")
    public Object listUnits(@ApiParam("单位名称") @RequestParam(value = "name", required = false) String name,
                            @ApiParam("单位层级：单位层级：2=地市级,  3=县级") @RequestParam(value = "scope", required = false) Integer scope,
                            @ApiParam("区域标签：Z=珠三角，Y=粤东西北") @RequestParam(value = "areaTag", required = false) String areaTag,
                            @ApiParam("页码，0开始") @RequestParam(value = "page", defaultValue = "0") int page,
                            @ApiParam("页长，默认20") @RequestParam(value = "pageSize", required = false) Integer pageSize,
                            @ApiIgnore List<Long> authorizedDomainIds) {
        int[] pagination = pageSize != null ? new int[] {page, pageSize} : new int[] {page};
        return unitService.listUnits(null, authorizedDomainIds, null, name, scope, Unit.SCOPE_MUNICIPAL, areaTag, pagination);
    }

    @ApiOperation("新建单位")
    @PostMapping("")
    @RequiresPermissions("units:global")
    @Traced
    public Object saveUnit(@ApiParam("单位信息") @RequestBody Unit unit) {
        unit.setId(null);
        unit.setShortPrefix(generateShortPrefix(unit));
        unitService.saveUnit(unit);
        String username = unit.getShortPrefix() + "_admin";
        Account account = authService.findAccount(username);
        if(account == null) {
            UnitMember member = new UnitMember();
            member.setUsername(username);
            member.setPassword(DEFAULT_PASSWORD);
            member.setNickname(username);
            member.setAvatar("/files/avatar/admin.png");
            member.setName(StringUtils.hasText(unit.getContactName()) ? unit.getContactName() : unit.getShortName());
            member.setPhone(unit.getContactPhone());
            member.setRoleKeys(Arrays.asList(ROLE_SUPERVISOR));
            saveMember(unit.getId(), member, null);
        }
        return unit;
    }

    private String generateShortPrefix(Unit unit) {
        String shortName = unit.getShortName();
        if(!StringUtils.hasText(shortName)) return null;
        String shortPrefix = PinyinUtils.getPinyinHeads(shortName);
        int index = 0;
        do {
            Unit existedUnit = unitService.getUnitByShortPrefix(shortPrefix);
            if(existedUnit == null || existedUnit.getId().equals(unit.getId())) return shortPrefix;
            shortPrefix = shortPrefix + ++index;
        } while(index < 10);
        return null;
    }

    private String testUsername(String inputUsername, Unit unit, String suffix) {
        String username = inputUsername;
        String shortPrefix = unit.getShortPrefix();
        if(!StringUtils.hasText(username)) {
            username = shortPrefix + suffix;
        }
        int index = 0;
        do {
            Account account = authService.findAccount(username);
            if(account == null) return username;
            username = shortPrefix + suffix + ++index;
        } while(index < 10);
        return null;
    }

    @ApiOperation("修改单位信息")
    @PostMapping("/{unitId}")
    @RequiresPermissions(value = {"units:global", "units:local"}, logical = Logical.OR)
    @Traced
    public Object saveUnit(@ApiParam("单位Id") @PathVariable("unitId") long unitId,
                           @ApiParam("单位信息") @RequestBody Unit unit,
                           @ApiIgnore List<Long> authorizedDomainIds) {
        assertAuthorizedUnit(unitId, authorizedDomainIds);
        unit.setId(unitId);
        unit.setShortPrefix(generateShortPrefix(unit));
        unitService.saveUnit(unit);
        return unit;
    }

    private static void assertAuthorizedUnit(Long unitId, List<Long> authorizedDomainIds) {
        if(authorizedDomainIds != null && !authorizedDomainIds.contains(unitId))
            throw new AuthorizationException("不具有访问该单位数据的权限" );
    }

    @ApiOperation("单位级别对应的角色列表")
    @GetMapping("/{unitId}/roles")
    @RequiresPermissions(value = {"units:global", "units:local"}, logical = Logical.OR)
    public Object listRoles(@ApiParam("单位Id") @PathVariable("unitId") long unitId,
                            @ApiIgnore List<Long> authorizedDomainIds) {
        assertAuthorizedUnit(unitId, authorizedDomainIds);
        Unit unit = unitService.getUnit(unitId);
        if(unit == null) throw new NotFoundException("无此单位");
        int scope = unit.getScope();
        //获取该单位层级的操作权限Role
        List<Role> preDefinedRoles = authService.findPreDefinedRoles();
        Set<String> opRoleNames = new HashSet<>();
        opRoleNames.add(ROLE_REPORTER);
        opRoleNames.add(ROLE_AUDITOR);
        opRoleNames.add(ROLE_SUPERVISOR);
        if(scope <= Unit.SCOPE_PROVINCIAL) {
            opRoleNames.add(ROLE_ADMINISTRATOR);
            opRoleNames.add(ROLE_STATISTICIAN);
        }
        List<Role> opRoles = preDefinedRoles.stream()
                .filter(role -> opRoleNames.contains(role.getKey()))
                .collect(Collectors.toList());
        //获取该单位层级的职能权限Role
        List<Role> definedRoles = authService.findDefinedRoles();
        List<Role> deptRoles;
        if(scope == Unit.SCOPE_COUNTY)
            deptRoles = definedRoles.stream()
                .filter(role -> {
                    String label = role.getKey();
                    return label.startsWith("县");
                }).collect(Collectors.toList());
        else if(scope == Unit.SCOPE_MUNICIPAL)
            deptRoles = definedRoles.stream()
                .filter(role -> {
                    String label = role.getKey();
                    return label.startsWith("市") || label.endsWith("科");
                }).collect(Collectors.toList());
        else
            deptRoles = definedRoles.stream()
                .filter(role -> {
                    String label = role.getKey();
                    return !(label.startsWith("县") || label.startsWith("市") || label.endsWith("科"));
                }).collect(Collectors.toList());
        Map<String, List<Role>> result = new HashMap<>();
        result.put("opRoles", opRoles);
        result.put("deptRoles", deptRoles);
        return result;
    }

    @ApiOperation("单位成员列表")
    @GetMapping("/{unitId}/members")
    @RequiresPermissions(value = {"units:global", "units:local"}, logical = Logical.OR)
    public Object listMembers(@ApiParam("单位Id") @PathVariable("unitId") long unitId,
                              @ApiIgnore List<Long> authorizedDomainIds) {
        assertAuthorizedUnit(unitId, authorizedDomainIds);
        return unitService.listMembers(unitId);
    }

    @ApiOperation("单位成员用户名建议")
    @GetMapping("/{unitId}/members/suggest-username")
    @RequiresPermissions(value = {"units:global", "units:local"}, logical = Logical.OR)
    public Object suggestUsername(@ApiParam("单位Id") @PathVariable("unitId") long unitId,
                                  @ApiParam("测试username") @RequestParam(value = "username", required = false) String username) {
        Unit unit = unitService.getUnit(unitId);
        return testUsername(username, unit, "_user");
    }

    @ApiOperation("新建单位成员")
    @PostMapping("/{unitId}/members")
    @RequiresPermissions(value = {"units:global", "units:local"}, logical = Logical.OR)
    @Traced
    public Object saveMember(@ApiParam("单位Id") @PathVariable("unitId") long unitId,
                             @ApiParam("账号信息") @RequestBody UnitMember member,
                             @ApiIgnore List<Long> authorizedDomainIds) {
        assertAuthorizedUnit(unitId, authorizedDomainIds);
        try {
            if(!StringUtils.hasText(member.getPassword())) member.setPassword(DEFAULT_PASSWORD);
            member.setUnitId(unitId);
            authService.createUserAndAccount(member, member.getUsername(), member.getPassword());
        } catch(DuplicateKeyException x) {
            throw new DuplicateKeyException("该登录名已存在");
        }
        authService.giveUserRoles(member.getId(), member.getRoleKeys().toArray(new String[member.getRoleKeys().size()]));
        return unitService.getMember(member.getId());
    }

    @ApiOperation("修改单位成员")
    @PostMapping("/{unitId}/members/{userId}")
    @RequiresPermissions(value = {"units:global", "units:local"}, logical = Logical.OR)
    @Traced
    public Object saveMember(@ApiParam("单位Id") @PathVariable("unitId") long unitId,
                             @ApiParam("成员id") @PathVariable("userId") long userId,
                             @ApiParam("账号信息") @RequestBody UnitMember member,
                             @ApiIgnore List<Long> authorizedDomainIds) {
        assertAuthorizedUnit(unitId, authorizedDomainIds);
        member.setId(userId);
        member.setUnitId(unitId);
        authService.updateUserAndPassword(member, member.getUsername(), member.getPassword());
        authService.ungiveUserRoles(member.getId());
        authService.giveUserRoles(member.getId(), member.getRoleKeys().toArray(new String[member.getRoleKeys().size()]));
        return unitService.getMember(member.getId());
    }

    @ApiOperation("删除单位")
    @DeleteMapping("/{unitId}")
    @RequiresRoles("users-op")
    @Traced
    public Object purgeUnit(@ApiParam("单位Id") @PathVariable("unitId") long unitId) {
        return unitService.purgeUnit(unitId);
    }

    @ApiOperation("删除账号")
    @DeleteMapping("/{unitId}/members/{userId}")
    @RequiresRoles("users-op")
    @Traced
    public Object purgeMember(@ApiParam("单位Id") @PathVariable("unitId") long unitId,
                              @ApiParam("成员id") @PathVariable("userId") long userId) {
        return unitService.purgeMember(userId);
    }

}
